package com.wngbms.async;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

@Slf4j
public class FutureDemo {
    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
//        ExecutorService executorService = Executors.newFixedThreadPool(10);
//        demo1(executorService);
//        executorService.shutdown();

//        demo2();

    }

    private static void demo2() throws InterruptedException, ExecutionException {
        FutureTask<String> ft2 = new FutureTask<>(new T2Task());
        FutureTask<String> ft1 = new FutureTask<>(new T1Task(ft2));

        new Thread(ft1).start();
        new Thread(ft2).start();

        log.info(ft1.get());
    }

    private static void demo1(ExecutorService executorService) {
        Future<?> future = executorService.submit(() -> {
            log.info("start");
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("end");
        });

//        f1(future);

        Future<String> future1 = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("call start");
                TimeUnit.SECONDS.sleep(10);
                log.info("call end");
                return "hello msfs2020";
            }
        });

//        f1(future1);

        Future<String> future2 = executorService.submit(() -> {
            log.info("start");
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("end");
        }, "result---");

//        f1(future2);

        ResultA resultA = new ResultA();
        resultA.setResult("pre result");

        Future<ResultA> future3 = executorService.submit(new TaskA(resultA), resultA);
//        f1(future3);

        FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("futureTask:{}", "start");
                return "futureTask return";
            }
        });
        new Thread(futureTask).start();

        f1(futureTask);
    }

    public static class T1Task implements Callable<String> {
        FutureTask<String> ft2;

        public T1Task(FutureTask<String> ft2) {
            this.ft2 = ft2;
        }

        @Override
        public String call() throws Exception {
            log.info("洗水壶");
            TimeUnit.SECONDS.sleep(1);

            log.info("烧开水");
            TimeUnit.SECONDS.sleep(15);

            String tf = ft2.get();
            log.info("拿到茶叶:{}", tf);

            log.info("泡茶");
            return "上茶" + tf;
        }
    }

    public static class T2Task implements Callable<String> {

        @Override
        public String call() throws Exception {
            log.info("洗茶壶");
            TimeUnit.SECONDS.sleep(1);

            log.info("洗茶杯");
            TimeUnit.SECONDS.sleep(2);

            log.info("拿茶叶");
            TimeUnit.SECONDS.sleep(1);
            return "龙井";
        }
    }

    @Data
    public static class ResultA {
        String result;
    }

    public static class TaskA implements Runnable {
        ResultA resultA;

        public TaskA(ResultA resultA) {
            this.resultA = resultA;
        }

        @Override
        public void run() {
            log.info("resultA:{}", resultA.getResult());
            resultA.setResult("my result");
        }
    }

    public static void f1(Future<?> future) {
        log.info("isDone:{} isCancel:{}", future.isDone(), future.isCancelled());

        try {
            log.info("get timeout:{}", future.get(5, TimeUnit.SECONDS));
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            log.info("get:{}", future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
